import { binaryAt } from '../utils'
import { sm } from './sm'
import { ir } from './ir'
import { decoder } from './decoder'
import { pc } from './pc'
import { psw } from './psw'
import { reg } from './reg'
import { multiplexer31 } from './mutiplexer31'
import { multiplexer21 } from './mutiplexer21'
import { au } from './au'
import { ram } from './ram'
import { input } from './input'
import { output } from './output'
import { IModule } from '../types'

interface IConSignal extends IModule {
    change: () => Promise<void>
}

/**
 * conSignal模块
 */
export const conSignal: IConSignal = {
    name: 'conSignal',
    async change() {
        // 从decoder模块获取指令
        const ins = decoder.state.ins
        // sm_en=~halt,
        sm.setState('sm_en', +(ins !== 'HALT'))
        // ir_ld=~sm,
        ir.setState('ld_ir', +!sm.state.sm_value)
        // pc_ld=(jg & g)|jmp,
        pc.setState(
            'ld_pc',
            +((ins === 'JG' && psw.state.gf === 1) || ins === 'JMP')
        )
        // pc_in=(~sm)|movi,
        pc.setState('in_pc', +(!sm.state.sm_value || ins === 'MOVI'))
        // reg_we=mova|movc|movd|movi|add|sub|in1,
        reg.setState(
            'we',
            +['MOVA', 'MOVC', 'MOVD', 'MOVI', 'ADD', 'SUB', 'IN'].includes(ins)
        )
        // reg_sr=ir[1:0],
        reg.setState('sr0', binaryAt(ir.state.value, 0))
        reg.setState('sr1', binaryAt(ir.state.value, 1))
        // reg_dr=ir[3:2],
        reg.setState('dr0', binaryAt(ir.state.value, 2))
        reg.setState('dr1', binaryAt(ir.state.value, 3))
        // s[1]=movb,
        multiplexer31.setState('s2', +(ins === 'MOVB'))
        // s[0]=movc,
        multiplexer31.setState('s1', +(ins === 'MOVC'))
        // mux_s=mova|movc|movi|add|sub|in1,
        multiplexer21.setState(
            's0',
            +['MOVA', 'MOVC', 'MOVI', 'ADD', 'SUB', 'IN'].includes(ins)
        )
        // au_ac=ir[7:4],
        au.setAc(ir.state.value >> 4)
        // ram_wr=movb,
        ram.setState('wr', +(ins === 'MOVB'))
        // ram_re=movc|movi|(~sm),
        ram.setState(
            're',
            +(['MOVC', 'MOVI'].includes(ins) || !sm.state.sm_value)
        )
        // gf_en=sub,
        psw.setState('g_en', +(ins === 'SUB'))
        // in_en=in1,
        input.setState('in_en', +(ins === 'IN'))
        // out_en=out1;
        output.setState('out_en', +(ins === 'OUT'))
    },
    init() {
        this.change()
    },
}
